package folder.main.exp3;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.math3.distribution.TDistribution;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

import folder.model.network.Network;
import folder.model.network.NetworkRandom;
import folder.model.node.Node;
import folder.model.virtual.VirtualNetwork;
import folder.model.virtual.VirtualNetworkRandom;

public class Exp3
{
	static int NUMBER_NODES = 20;
	static int NUMBER_LINKS = 90;	// Min 30
	
	static final String FILE_1_NAME = "C:/Users/aurelioj/Google Drive/R/Experimento2/File1DelayFull.txt";
	static final String FILE_2_NAME = "C:/Users/aurelioj/Google Drive/R/Experimento2/File2Relation.txt";
	static final String FILE_3_NAME = "C:/Users/aurelioj/Google Drive/R/Experimento2/File3OccupationPerc.txt";
	
	static int NUMBER_VIRTUAL_NETWORKS_70 = 129;
	static int NUMBER_VIRTUAL_NETWORKS_80 = 157;
	static int NUMBER_VIRTUAL_NETWORKS_90 = 196;
	
	static List< VirtualNetwork > virtualNetworks70 = setVirtualNetworks( NUMBER_VIRTUAL_NETWORKS_70 );
	static List< VirtualNetwork > virtualNetworks80 = setVirtualNetworks( NUMBER_VIRTUAL_NETWORKS_80 );
	static List< VirtualNetwork > virtualNetworks90 = setVirtualNetworks( NUMBER_VIRTUAL_NETWORKS_90 );
	
	static List< VirtualNetwork > setVirtualNetworks( int numberVirtualNetworks )
	{
		List< VirtualNetwork > virtualNetworks = new ArrayList< VirtualNetwork >();
		
		for( int i = 0; i < numberVirtualNetworks; i++ )
		{
			VirtualNetwork virtualNetworkRandom = VirtualNetworkRandom.virtualNetworkRandom( i );
			virtualNetworks.add( virtualNetworkRandom );
		}
		
		return virtualNetworks;
	}
	
	static final SummaryStatistics sumDelayFull0 = new SummaryStatistics();
	
	static final SummaryStatistics sumDelayFull70 = new SummaryStatistics();
	static final SummaryStatistics sumRelation70 = new SummaryStatistics();
	static final SummaryStatistics sumOccupation70 = new SummaryStatistics();
	
	static final SummaryStatistics sumDelayFull80 = new SummaryStatistics();
	static final SummaryStatistics sumRelation80 = new SummaryStatistics();
	static final SummaryStatistics sumOccupation80 = new SummaryStatistics();
	
	static final SummaryStatistics sumDelayFull90 = new SummaryStatistics();
	static final SummaryStatistics sumRelation90 = new SummaryStatistics();
	static final SummaryStatistics sumOccupation90 = new SummaryStatistics();
	
	static final int NUMBER_EVALUATIONS = 1000;
	static int identifierEvaluation = 0;
	static Network network;
	
	public static void main( String[] args )
	{
		while( identifierEvaluation < NUMBER_EVALUATIONS )
		{
			network = NetworkRandom.networkRandom( NUMBER_NODES, NUMBER_LINKS );
			network.setPathsNetwork();
			double delayFull0 = getDelayMax();
			
			double delayFull70 = 0;
			double occupation70 = 0;
			boolean check70 = false;
			
			if( allocateVirtualNetworks( virtualNetworks70 ) )
			{
				network.setPathsNetwork();
				delayFull70 = getDelayMax();
				occupation70 = Exp3.getPercentageOccupation();
				
				if( delayFull70 < Double.POSITIVE_INFINITY )
					check70 = true;
				else
					check70 = false;
				
				release( virtualNetworks70 );
			}
			
			double delayFull80 = 0;
			double occupation80 = 0;
			boolean check80 = false;
			
			if( check70 && allocateVirtualNetworks( virtualNetworks80 ) )
			{
				network.setPathsNetwork();
				delayFull80 = getDelayMax();
				occupation80 = Exp3.getPercentageOccupation();
				
				if( delayFull80 < Double.POSITIVE_INFINITY )
					check80 = true;
				else
					check80 = false;
				
				release( virtualNetworks80 );
			}
			
			double delayFull90 = 0;
			double occupation90 = 0;
			boolean check90 = false;
			
			if( check80 && allocateVirtualNetworks( virtualNetworks90 ) )
			{
				network.setPathsNetwork();
				delayFull90 = getDelayMax();
				occupation90 = Exp3.getPercentageOccupation();
				
				if( delayFull90 < Double.POSITIVE_INFINITY )
					check90 = true;
				else
					check90 = false;
				
				release( virtualNetworks90 );
			}
			
			if( check70 && check80 && check90 )
			{
				sumDelayFull0.addValue( delayFull0 );
				
				sumDelayFull70.addValue( delayFull70 );
				sumRelation70.addValue( delayFull70 / delayFull0 );
				sumOccupation70.addValue( occupation70 );
				
				sumDelayFull80.addValue( delayFull80 );
				sumRelation80.addValue( delayFull80 / delayFull0 );
				sumOccupation80.addValue( occupation80 );
				
				sumDelayFull90.addValue( delayFull90 );
				sumRelation90.addValue( delayFull90 / delayFull0 );
				sumOccupation90.addValue( occupation90 );
				
				identifierEvaluation++;
				System.out.println( identifierEvaluation );
			}
		}
		
		printAndSaveToFile();
	}
	
	static double getDelayMax()
	{		
		SummaryStatistics sum = new SummaryStatistics();
		
		for( Node node: network.getNodes() )
			sum.addValue( node.getDelayToNodeTargetMean() );
		
		return sum.getMax();
	}
	
	static void release( List< VirtualNetwork > virtualNetworks )
	{
		for( VirtualNetwork virtualNetwork: virtualNetworks )
			network.release( virtualNetwork );
	}
	
	static boolean allocateVirtualNetworks( List< VirtualNetwork > virtualNetworks )
	{
		for( VirtualNetwork virtualNetwork: virtualNetworks )
			if( !network.allocate( virtualNetwork ) )
				return false;
		
		return true;
	}
	
	static double getPercentageOccupation()
	{
		double percentageOccupation = 0;
		
		for( Node node: network.getNodes() )
		{
			node.setBandwidthOccupation();
			
			if( node.getBandwidthOccupation() > percentageOccupation )
				percentageOccupation = node.getBandwidthOccupation();
		}
		
		return percentageOccupation;
	}
	
	static void printAndSaveToFile()
	{
		DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();
		decimalFormatSymbols.setDecimalSeparator( '.' );
		
		DecimalFormat decimalFormat = new DecimalFormat( "0.00", decimalFormatSymbols );
		
		double factor = 1000000;
		
		String strDelayFull0  = getStringOfData( sumDelayFull0, decimalFormat, factor );
		String strDelayFull70 = getStringOfData( sumDelayFull70, decimalFormat, factor );
		String strDelayFull80 = getStringOfData( sumDelayFull80, decimalFormat, factor );
		String strDelayFull90 = getStringOfData( sumDelayFull90, decimalFormat, factor );
		String strDelayFull = strDelayFull0 + strDelayFull70 + strDelayFull80 + strDelayFull90;
				
		String strRelation70 = getStringOfData( sumRelation70, decimalFormat, 1 );
		String strRelation80 = getStringOfData( sumRelation80, decimalFormat, 1 );
		String strRelation90 = getStringOfData( sumRelation90, decimalFormat, 1 );
		String strRelation = strRelation70 + strRelation80 + strRelation90;
				
		String strOccupation70 = getStringOfData( sumOccupation70, decimalFormat, 100 );
		String strOccupation80 = getStringOfData( sumOccupation80, decimalFormat, 100 );
		String strOccupation90 = getStringOfData( sumOccupation90, decimalFormat, 100 );
		String strOccupation = strOccupation70 + strOccupation80 + strOccupation90;
		
		addDataToFile( strDelayFull, FILE_1_NAME );
		addDataToFile( strRelation, FILE_2_NAME );
		addDataToFile( strOccupation, FILE_3_NAME );
		
		System.out.println( "Number of evaluations: " + NUMBER_EVALUATIONS );
		System.out.println( "Number of links: " + network.getLinks().size() );
		
		System.out.println( "DelayFull0: \t" + strDelayFull0 );
		
		System.out.println( "Number of VNs: " + NUMBER_VIRTUAL_NETWORKS_70 );
		System.out.println( "DelayFull70: \t" + strDelayFull70 );
		System.out.println( "Relation70: \t" + strRelation70 );
		System.out.println( "Occupation70: \t" + strOccupation70 );
		
		System.out.println( "Number of VNs: " + NUMBER_VIRTUAL_NETWORKS_80 );
		System.out.println( "DelayFull80: \t" + strDelayFull80 );
		System.out.println( "Relation80: \t" + strRelation80 );
		System.out.println( "Occupation80: \t" + strOccupation80 );
		
		System.out.println( "Number of VNs: " + NUMBER_VIRTUAL_NETWORKS_90 );
		System.out.println( "DelayFull90: \t" + strDelayFull90 );
		System.out.println( "Relation90: \t" + strRelation90 );
		System.out.println( "Occupation90: \t" + strOccupation90 );
	}
	
	static void addDataToFile( String data, String fileName )
	{
		try {
			FileWriter fileWriter = new FileWriter( fileName, true );
			PrintWriter printWriter = new PrintWriter( fileWriter );
			printWriter.println( data );
			printWriter.close();
			
		} catch (IOException e) {e.printStackTrace();}
	}
	
	static String getStringOfData( SummaryStatistics sum, DecimalFormat decimalFormat, double factor )
	{
		double mean = sum.getMean();
		double width = getConfidenceIntervalWidth( sum, 0.05 );
		return ( decimalFormat.format( mean * factor ) ) + "\t" + decimalFormat.format( ( mean - width ) * factor ) + "\t" + decimalFormat.format( ( mean + width ) * factor ) + "\t";
	}
	
	static double getConfidenceIntervalWidth( SummaryStatistics sum, double significance ) //throws MathException
	{
		if( sum.getN() == 0 )
			return 0;
		
		long N = sum.getN() > 1 ? sum.getN() : 2;
				
		TDistribution tDist = new TDistribution( N - 1 );
		double a = tDist.inverseCumulativeProbability( 1.0 - significance / 2 );
		return a * sum.getStandardDeviation() / Math.sqrt( sum.getN() );
	}
	
}
